﻿// -------------------------------------------------------------------------
//    @FileName         :    NFServicePackage.cpp
//    @Author           :    gaoyi
//    @Date             :    2025/1/2
//    @Email            :    445267987@qq.com
//    @Module           :    NFServicePackage
//
// -------------------------------------------------------------------------

// --- 文件总结 ---------------------------------------------------------------
// 本文件实现 NFServicePackage 类的所有静态服务函数：
// 
// 【背包查询】
// - GetBagPage：获取指定类型的背包页签
// - GetMoney/GetMoneyNumber/SetMoneyNumber：金钱相关查询和设置
// 
// 【物品添加】
// - AddToBag：添加物品到背包（单个/批量）
// - AddToBagPage：添加物品到指定背包页签
// - AddItems：添加物品列表（支持剩余物品返回）
// - AddByItemIDAndNum：根据物品ID和数量添加
// - AddItemsByItemIDAndNum：批量添加物品
// - AddByItem：添加物品对象
// 
// 【物品查询】
// - GetAllItemTotalNum：获取所有背包中指定物品的总数
// - GetItemTotalNum：获取指定物品的总数
// - GetItem：获取指定格子/背包的物品
// - GetItemByUUID：根据UUID获取物品
// - GetItemByItemId：根据物品ID获取物品
// - GetItemByItemIdAndUUID：根据物品ID和UUID获取物品
// 
// 【物品删除】
// - DelItems：删除物品列表
// - DelItemByItemIDAndNum：根据物品ID和数量删除
// - DelAllItemByItemID：删除所有指定物品ID的物品
// - DelItemByNumWithGrid：根据格子位置和数量删除
// - DelItemByGrid：根据格子位置删除
// 
// 【其他功能】
// - OnVirtualMoneyInc：虚拟货币增加回调
// - CheckUseLimite/OnUse：物品使用限制检查
// - IsTempStorageHasItem：检查临时存储是否有物品
// ---------------------------------------------------------------------------

#include "NFServicePackage.h"

#include <NFLogicCommon/BagPage/NFBagPageOp.h>
#include <NFBagPageOpMgr.h>
#include <NFPackageUtil.h>

#include "NFPlayer.h"
#include "NFPackagePart.h"
#include "NFPlayerUtil.h"
#include "NFLogicCommon/BagPage/NFBagDefine.h"

NFBagPage* NFServicePackage::GetBagPage(NFPlayer* pPlayer, int iBagType)
{
    CHECK_NULL_RE_NULL(0, pPlayer, "iBagType:{}", iBagType);
    NFPackagePart* pPackagePart = pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    CHECK_NULL_RE_NULL(pPlayer->GetRoleID(), pPackagePart, "iBagType:{}", iBagType);

    return pPackagePart->GetPageByType(iBagType);
}

Money* NFServicePackage::GetMoney(NFPlayer* pPlayer, int iMoneyType)
{
    CHECK_NULL_RE_NULL(0, pPlayer, "iMoneyType:{}", iMoneyType);
    NFPackagePart* pPackagePart = pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    CHECK_NULL_RE_NULL(pPlayer->GetRoleID(), pPackagePart, "iMoneyType:{}", iMoneyType);

    return pPackagePart->GetMoney(iMoneyType);
}

int64_t NFServicePackage::GetMoneyNumber(NFPlayer* pPlayer, int iMoneyType)
{
    CHECK_NULL(0, pPlayer);
    Money* pMoney = GetMoney(pPlayer, iMoneyType);
    CHECK_NULL_WF(pPlayer->GetRoleID(), pMoney, "iMoneyType:{}", iMoneyType);

    return pMoney->value;
}

int NFServicePackage::SetMoneyNumber(NFPlayer* pPlayer, int iMoneyType, int64_t llMoneyNum)
{
    CHECK_NULL_WF(0, pPlayer, "iMoneyType:{}", iMoneyType);
    NFPackagePart* pPackagePart = pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    CHECK_NULL_WF(pPlayer->GetRoleID(), pPackagePart, "iMoneyType:{}", iMoneyType);

    return pPackagePart->SetMoneyNumber(iMoneyType, llMoneyNum);
}

int NFServicePackage::AddToBag(NFPlayer* pPlayer, int enReason, WillAddItemData& stWillAddItemData, int iNum, bool bAsPossible, int* pAddedNum)
{
    int iRetCode = 0;
    CHECK_NULL(0, pPlayer);
    NFBagPageOpMgr stBagPageOpMgr(pPlayer, enReason, true);
    iRetCode = stBagPageOpMgr.AddToBag(stWillAddItemData, iNum, bAsPossible, pAddedNum);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "iRetCode:{}", iRetCode);

    iRetCode = stBagPageOpMgr.Commit(true);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "Commit iRetCode:{}", iRetCode);
    return 0;
}

int NFServicePackage::AddToBag(NFPlayer* const pPlayer, int enReason, std::vector<WillAddItemData>& astWillAddItemData, std::vector<int>& aiWantAddNum, bool bAsPossible, std::vector<int>* paiAddedNum)
{
    int iRetCode = 0;
    CHECK_NULL(0, pPlayer);
    NFBagPageOpMgr stBagPageOpMgr(pPlayer, enReason, true);
    iRetCode = stBagPageOpMgr.AddToBag(astWillAddItemData, aiWantAddNum, bAsPossible, paiAddedNum);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "iRetCode:{}", iRetCode);

    iRetCode = stBagPageOpMgr.Commit(true);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "Commit iRetCode:{}", iRetCode);
    return 0;
}

int NFServicePackage::AddToBagPage(NFPlayer* pPlayer, int enReason, WillAddItemData& stWillAddItemData, int iNum, int iBagType, bool bAsPossible, int* pAddedNum)
{
    int iRetCode = 0;
    CHECK_NULL(0, pPlayer);
    NFBagPageOpMgr stBagPageOpMgr(pPlayer, enReason, true);
    iRetCode = stBagPageOpMgr.AddToBagPage(stWillAddItemData, iNum, iBagType, bAsPossible, pAddedNum);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "iRetCode:{}", iRetCode);

    iRetCode = stBagPageOpMgr.Commit(true);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "Commit iRetCode:{}", iRetCode);
    return 0;
}

int NFServicePackage::AddItems(NFPlayer* pPlayer, const std::vector<Item>& vecItems, int enPackageOpReason, bool bAsPossible, std::vector<Item>* pvecLeftItems, bool bSyncToClient)
{
    int iRetCode = 0;
    CHECK_NULL(0, pPlayer);
    NFBagPageOpMgr stBagPageOpMgr(pPlayer, enPackageOpReason, true);
    iRetCode = stBagPageOpMgr.AddItems(vecItems, bAsPossible, pvecLeftItems);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "iRetCode:{}", iRetCode);

    iRetCode = stBagPageOpMgr.Commit(bSyncToClient);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "Commit iRetCode:{}", iRetCode);
    return 0;
}

int NFServicePackage::AddByItemIDAndNum(NFPlayer* pPlayer, int enReason, int iItemID, int iNum, int iBagType, enItemBindType enBindType)
{
    CHECK_NULL(0, pPlayer);
    int iRetCode = 0;

    WillAddItemData stWillAddItemData;
    stWillAddItemData.id = iItemID;

    NFBagPageOpMgr stBagPageOpMgr(pPlayer, enReason, true);
    stBagPageOpMgr.SetBindStatForAdd(enBindType);

    if (!NFItemUtil::IsValidBagType(iBagType))
    {
        iRetCode = stBagPageOpMgr.AddToBag(stWillAddItemData, iNum);
        CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "iRetCode:{}", iRetCode);
    }
    else
    {
        iRetCode = stBagPageOpMgr.AddToBagPage(stWillAddItemData, iNum, iBagType);
        CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "iRetCode:{}", iRetCode);
    }

    iRetCode = stBagPageOpMgr.Commit(true);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "Commit iRetCode:{}", iRetCode);
    return 0;
}

int NFServicePackage::AddItemsByItemIDAndNum(NFPlayer* pPlayer, const std::vector<Item>& astItemOne, int enReason, bool bIsCommit, enItemBindType enBindType)
{
    int iRetCode = 0;
    CHECK_NULL(0, pPlayer);
    NFBagPageOpMgr stBagPageOpMgr(pPlayer, enReason, bIsCommit);
    stBagPageOpMgr.SetBindStatForAdd(enBindType);
    iRetCode = stBagPageOpMgr.AddItems(astItemOne, true);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "iRetCode:{}", iRetCode);

    if (bIsCommit)
    {
        iRetCode = stBagPageOpMgr.Commit(true);
        CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "Commit iRetCode:{}", iRetCode);
    }
    return 0;
}

int NFServicePackage::AddByItem(NFPlayer* pPlayer, int enReason, NFGridItem* pItem, bool bCommit)
{
    int iRetCode = 0;
    CHECK_NULL(0, pPlayer);
    NFBagPageOpMgr stBagPageOpMgr(pPlayer, enReason, bCommit);
    iRetCode = stBagPageOpMgr.AddToBag(*pItem, pItem->GetNumber());
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "iRetCode:{}", iRetCode);

    if (bCommit)
    {
        iRetCode = stBagPageOpMgr.Commit(true);
        CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "Commit iRetCode:{}", iRetCode);
    }
    return 0;
}

int NFServicePackage::GetAllItemTotalNum(NFPlayer* pPlayer, int iItemID, int& iTotalNum)
{
    CHECK_NULL(0, pPlayer);
    NFPackagePart* pPackagePart = pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    CHECK_NULL(pPlayer->GetRoleID(), pPackagePart);

    if (NFItemUtil::IsValidMoney(iItemID))
    {
        iTotalNum = pPackagePart->GetMoneyNumber(iItemID);
        return 0;
    }

    for (int i = 0; i < (int)g_personAllOpBagType.size(); ++i)
    {
        iTotalNum += pPackagePart->GetItemNum(g_personAllOpBagType[i], iItemID);
    }
    return 0;
}

int NFServicePackage::GetItemTotalNum(NFPlayer* pPlayer, int iItemID, int& iTotalNum)
{
    int iRetCode = 0;
    CHECK_NULL(0, pPlayer);
    NFPackagePart* pPackagePart = pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    CHECK_NULL(pPlayer->GetRoleID(), pPackagePart);

    if (NFItemUtil::IsValidMoney(iItemID))
    {
        iTotalNum = pPackagePart->GetMoneyNumber(iItemID);
        return 0;
    }

    int iBagType = 0;
    iRetCode = NFItemUtil::CalcAddBagType(iItemID, 0, iBagType);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "NFPackageUtil::CalcAddBagType");

    iTotalNum = pPackagePart->GetItemNum(iBagType, iItemID);
    return 0;
}

int NFServicePackage::GetItemTotalNum(NFPlayer* pPlayer, int iItemID)
{
    int iTotalNum = 0;
    int iRetCode = 0;
    iRetCode = GetItemTotalNum(pPlayer, iItemID, iTotalNum);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "GetItemTotalNum:{}", iItemID);

    return iTotalNum;
}

int NFServicePackage::GetItem(NFPlayer* pPlayer, int iBagType, int iGridIndex, NFGridItem* pItemOut)
{
    CHECK_NULL(0, pPlayer);
    NFPackagePart* pPackagePart = pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    CHECK_NULL(pPlayer->GetRoleID(), pPackagePart);

    return pPackagePart->GetItem(iBagType, iGridIndex, pItemOut);
}

int NFServicePackage::GetItem(NFPlayer* pPlayer, int iBagType, std::vector<NFGridItem>& aWearList)
{
    CHECK_NULL(0, pPlayer);
    NFPackagePart* pPackagePart = pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    CHECK_NULL(pPlayer->GetRoleID(), pPackagePart);

    return pPackagePart->GetItem(iBagType, aWearList);
}

int NFServicePackage::GetItemByUUID(NFPlayer* pPlayer, int iBagType, uint64_t ullUUID, NFGridItem* pItemOut)
{
    CHECK_NULL(0, pPlayer);
    NFPackagePart* pPackagePart = pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    CHECK_NULL(pPlayer->GetRoleID(), pPackagePart);

    return pPackagePart->GetItemByUUID(iBagType, ullUUID, pItemOut);
}

NFGridItem* NFServicePackage::GetItemByUUID(NFPlayer* pPlayer, int iBagType, uint64_t ullUUID)
{
    CHECK_NULL_RE_NULL(0, pPlayer, "");
    NFPackagePart* pPackagePart = pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    CHECK_NULL_RE_NULL(pPlayer->GetRoleID(), pPackagePart, "");

    return pPackagePart->GetItemByUUID(iBagType, ullUUID);
}

int NFServicePackage::GetItemByItemIdAndUUID(NFPlayer* pPlayer, int iItemID, uint64_t ullUUID, NFGridItem* pItemOut)
{
    CHECK_NULL(0, pPlayer);
    int iBagType = 0;
    int iRetCode = NFItemUtil::GetSuitableBag(iItemID, 0, iBagType);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "NFPackageUtil::GetSuitableBag, iItemID:{}", iItemID);

    return GetItemByUUID(pPlayer, iBagType, ullUUID, pItemOut);
}

NFGridItem* NFServicePackage::GetItemByItemIdAndUUID(NFPlayer* pPlayer, int iItemID, uint64_t ullUUID)
{
    CHECK_NULL_RE_NULL(0, pPlayer, "");
    int iBagType = 0;
    int iRetCode = NFItemUtil::GetSuitableBag(iItemID, 0, iBagType);
    CHECK_ERR_RE_NULL(pPlayer->GetRoleID(), iRetCode, "NFPackageUtil::GetSuitableBag, iItemID:{}", iItemID);

    return GetItemByUUID(pPlayer, iBagType, ullUUID);
}

int NFServicePackage::GetItemByItemId(NFPlayer* pPlayer, int iBagType, int iItemID, NFGridItem* pItemOut)
{
    CHECK_NULL(0, pPlayer);
    NFPackagePart* pPackagePart = pPlayer->GetPart<NFPackagePart>(PART_PACKAGE);
    CHECK_NULL(pPlayer->GetRoleID(), pPackagePart);

    return pPackagePart->GetItemByItemId(iBagType, iItemID, pItemOut);
}

int NFServicePackage::DelItems(NFPlayer* pPlayer, std::vector<DelItemData>& vecDelWareDatas, int enPackageOpReason, bool bCompareResult)
{
    int iRetCode = 0;
    CHECK_NULL(0, pPlayer);
    NFBagPageOpMgr stBagPageOpMgr(pPlayer, enPackageOpReason, true);

    std::vector<int> vecBagTypes;
    // 添加需要查找的容器 从物品推荐的容器中找
    for (auto const& stDelWareData : vecDelWareDatas)
    {
        int iBagType = 0;
        iRetCode = NFItemUtil::GetSuitableBag(stDelWareData.m_iWareID, enPackageOpReason, iBagType);
        CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "CServicePackage::GetSuitableTab");
        vecBagTypes.push_back(iBagType);
    }

    // 添加推荐删除的页签
    iRetCode = stBagPageOpMgr.AddBagPageOp(vecBagTypes);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "stCWareContainersOp.AddBagContainerOp");

    for (int i = 0; i < (int)vecDelWareDatas.size(); i++)
    {
        DelItemData& delItem = vecDelWareDatas[i];
        iRetCode = stBagPageOpMgr.DelAllItems(delItem.m_iWareID, delItem.m_iWantDelNum, &delItem.m_iRealDelNum);
        CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "DelItems");
    }

    // 比较结果
    if (bCompareResult)
    {
        for (auto const& delResult : vecDelWareDatas)
        {
            if (delResult.m_iRealDelNum != delResult.m_iWantDelNum)
            {
                CHECK_WARN(pPlayer->GetRoleID(), ERR_CODE_ITEM_NOT_ENOUGH
                           , "Item Not Enough m_iWareID:%d want:%d del:%d"
                           , delResult.m_iWareID, delResult.m_iWantDelNum, delResult.m_iRealDelNum);
            }
        }
    }

    iRetCode = stBagPageOpMgr.Commit(true);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "Commit iRetCode:{}", iRetCode);
    return 0;
}

int NFServicePackage::DelItemByItemIDAndNum(NFPlayer* pPlayer, int enReason, int iItemID, int iNum, int* piDelNum)
{
    int iRetCode = 0;
    CHECK_NULL(0, pPlayer);
    NFBagPageOpMgr stBagPageOpMgr(pPlayer, enReason, true);

    WillDelItemData stDelItemData;
    stDelItemData.m_iItemID = iItemID;
    stDelItemData.m_iWantDelNum = iNum;

    iRetCode = stBagPageOpMgr.DelItems(stDelItemData, piDelNum);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "DelItems");

    iRetCode = stBagPageOpMgr.Commit(true);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "Commit iRetCode:{}", iRetCode);
    return 0;
}

int NFServicePackage::DelAllItemByItemID(NFPlayer* pPlayer, int enReason, int iItemID, int iBagType)
{
    int iRetCode = 0;
    CHECK_NULL(0, pPlayer);
    NFBagPageOpMgr stBagPageOpMgr(pPlayer, enReason, true);

    if (iBagType == 0)
    {
        stBagPageOpMgr.AddAllBagPage();
        stBagPageOpMgr.ForEachBagPageOp([&](NFBagPageOp& op, bool& bStop) -> int
        {
            iRetCode = op.DelAllByItemID(iItemID);
            CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "DelAllByItemID");
            return 0;
        });
    }
    else
    {
        NFBagPageOp* pBagPageOp = stBagPageOpMgr.GetBagPageOpByBagType(iBagType);
        CHECK_NULL_WF(pPlayer->GetRoleID(), pBagPageOp, "iBagType:{}", iBagType);

        iRetCode = pBagPageOp->DelAllByItemID(iItemID);
        CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "DelAllByItemID");
    }

    iRetCode = stBagPageOpMgr.Commit(true);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "Commit iRetCode:{}", iRetCode);

    return 0;
}

int NFServicePackage::DelItemByNumWithGrid(NFPlayer* pPlayer, int enReason, int iGridIndex, int iNum, int iBagType)
{
    int iRetCode = 0;
    CHECK_NULL(0, pPlayer);
    NFBagPageOpMgr stBagPageOpMgr(pPlayer, enReason, true);

    NFBagPageOp* pBagPageOp = stBagPageOpMgr.GetBagPageOpByBagType(iBagType);
    CHECK_NULL_WF(pPlayer->GetRoleID(), pBagPageOp, "iBagType:{}", iBagType);

    iRetCode = pBagPageOp->DelItemByGridWithNum(iGridIndex, iNum);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "DelAllByItemID");

    iRetCode = stBagPageOpMgr.Commit(true);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "Commit iRetCode:{}", iRetCode);
    return 0;
}

int NFServicePackage::DelItemByGrid(NFPlayer* pPlayer, int enReason, int iGridIndex, int iBagType)
{
    int iRetCode = 0;
    CHECK_NULL(0, pPlayer);
    NFBagPageOpMgr stBagPageOpMgr(pPlayer, enReason, true);

    NFBagPageOp* pBagPageOp = stBagPageOpMgr.GetBagPageOpByBagType(iBagType);
    CHECK_NULL_WF(pPlayer->GetRoleID(), pBagPageOp, "iBagType:{}", iBagType);

    iRetCode = pBagPageOp->DelItemByGrid(iGridIndex);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "DelAllByItemID");

    iRetCode = stBagPageOpMgr.Commit(true);
    CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "Commit iRetCode:{}", iRetCode);
    return 0;
}

int NFServicePackage::OnVirtualMoneyInc(NFPlayer* pPlayer, int moneyType, int64_t value, int reason, int subReason)
{
    CHECK_NULL(0, pPlayer);
    if (value <= 0)
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "virtual money inc value must > 0, moneyType:{} value:{} reason:{} subReason:{}", moneyType, value, reason, subReason);
        return -1;
    }

    int iRetCode = 0;
    if (moneyType == EN_ID_EXP)
    {
        iRetCode = NFPlayerUtil::AddExp(pPlayer, value, reason, subReason);
        CHECK_ERR(pPlayer->GetRoleID(), iRetCode, "AddExp Failed, moneyType:{} value:{} reason:{} subReason:{}", moneyType, value, reason, subReason);
    }
    else
    {
        LOG_ERR(pPlayer->GetRoleID(), -1, "unknown virtual money inc value, moneyType:{} value:{} reason:{} subReason:{}", moneyType, value, reason, subReason);
        return -1;
    }
    return 0;
}

int NFServicePackage::CheckUseLimite(NFPlayer* pPlayer, int iItemId, int iNum)
{
    CHECK_NULL(0, pPlayer);
    auto pPart = pPlayer->GetPart<NFPackagePart>();
    CHECK_NULL(pPlayer->GetRoleID(), pPart);
    return pPart->CheckUseLimite(iItemId, iNum);
}

int NFServicePackage::OnUse(NFPlayer* pPlayer, int iItemId, int iNum)
{
    CHECK_NULL(0, pPlayer);
    auto pPart = pPlayer->GetPart<NFPackagePart>();
    CHECK_NULL(pPlayer->GetRoleID(), pPart);
    return pPart->OnUse(iItemId, iNum);
}

bool NFServicePackage::IsTempStorageHasItem(NFPlayer* pPlayer)
{
    CHECK_NULL_RE_FALSE(0, pPlayer);
    auto pPart = pPlayer->GetPart<NFPackagePart>();
    CHECK_NULL_RE_FALSE(pPlayer->GetRoleID(), pPart);
    return pPart->IsTempStorageHasItem();
}
